﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Diagnostics;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Security.Cryptography.X509Certificates;
using Sinacor.Infra.Service.Security.Authentication.ServiceCredentials;
using Sinacor.Infra.Service.SecurityTokenService.Services.ServiceContracts;
using Sinacor.Infra.Service.SecurityTokenService.Services.ServiceImplementations;
using Sinacor.Infra.Common.Security.Authentication.Credentials;
using System.ServiceModel.Security.Tokens;

namespace STSHosterService
{
    public class StsHost
    {
        ServiceHost host;

        /// <summary>
        /// 
        /// </summary>
        public StsHost()
        {

        }

        /// <summary>
        /// Inicializa o serviço STS
        /// </summary>
        public void Initialize()
        {

            try
            {
                host = new ServiceHost(typeof(SecurityTokenService));

                SinacorServiceCredentials serviceCredential = new SinacorServiceCredentials();

                serviceCredential.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.TrustedPeople, X509FindType.FindBySubjectDistinguishedName, "CN=SinacorSTSAuthority");

                host.Description.Behaviors.Remove((typeof(ServiceCredentials)));
                host.Description.Behaviors.Add(serviceCredential);

                Binding sinacorHttpBinding = CreateSinacorBinding();
                Binding sinacorTcpBinding = CreateSinacorTcpBinding();

                host.AddServiceEndpoint(typeof(ISecurityTokenService), sinacorHttpBinding, "http://localhost:62002/SecurityTokenService");
                host.AddServiceEndpoint(typeof(ISecurityTokenService), sinacorTcpBinding, "net.tcp://localhost:62000/SecurityTokenService");

                host.Open();
            }
            catch (Exception ex)
            {
                throw new Exception("Could not start STS Service", ex);
                //EventLog.WriteEntry("STS Hoster", "Could not start STS Service. \n"
                //                                       + ex.Message + "\n" + ex.StackTrace);
            }
        }

        /// <summary>
        /// Cria o binding para o serviço STS
        /// </summary>
        /// <returns></returns>
        private static Binding CreateSinacorBinding()
        {
            HttpTransportBindingElement httpTransport = new HttpTransportBindingElement();

            SymmetricSecurityBindingElement messageSecurity = new SymmetricSecurityBindingElement();

            messageSecurity.LocalClientSettings.MaxClockSkew = new TimeSpan(1, 0, 0);
            messageSecurity.LocalServiceSettings.MaxClockSkew = new TimeSpan(1, 0, 0);

            messageSecurity.EndpointSupportingTokenParameters.SignedEncrypted.Add(new SinacorTokenParameters());
            X509SecurityTokenParameters x509ProtectionParameters = new X509SecurityTokenParameters();
            x509ProtectionParameters.InclusionMode = SecurityTokenInclusionMode.Never;
            messageSecurity.ProtectionTokenParameters = x509ProtectionParameters;
            return new CustomBinding(messageSecurity, httpTransport);
        }

        /// <summary>
        /// Cria o binding para o serviço STS
        /// </summary>
        /// <returns></returns>
        private static Binding CreateSinacorTcpBinding()
        {
            TcpTransportBindingElement tcpTransport = new TcpTransportBindingElement();
            tcpTransport.PortSharingEnabled = true;

            SymmetricSecurityBindingElement messageSecurity = new SymmetricSecurityBindingElement();

            messageSecurity.LocalClientSettings.MaxClockSkew = new TimeSpan(1, 0, 0);
            messageSecurity.LocalServiceSettings.MaxClockSkew = new TimeSpan(1, 0, 0);

            messageSecurity.EndpointSupportingTokenParameters.SignedEncrypted.Add(new SinacorTokenParameters());
            X509SecurityTokenParameters x509ProtectionParameters = new X509SecurityTokenParameters();
            x509ProtectionParameters.InclusionMode = SecurityTokenInclusionMode.Never;
            messageSecurity.ProtectionTokenParameters = x509ProtectionParameters;

            SecurityBindingElement security =
                SecurityBindingElement.CreateSecureConversationBindingElement(messageSecurity);


            //Definição da Formatação da mensagem
            BinaryMessageEncodingBindingElement messageEncoding = new BinaryMessageEncodingBindingElement();

            return new CustomBinding(security, messageEncoding,tcpTransport);
        }


        /// <summary>
        /// Para o serviço STS
        /// </summary>
        public void Finalize()
        {
            if (host.State == CommunicationState.Opened)
                host.Close();
        }

    }
}
